#include "d3dUtility.h"

struct ColorVertex
{
	float _x, _y, _z;
	D3DCOLOR _color;
	ColorVertex() {}
	ColorVertex(float x, float y, float z, D3DCOLOR color)
	{
		_x = x; _y = y; _z = z; _color = color;
	}
	static const DWORD FVF;
};
const DWORD ColorVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;

D3DMATRIX g_WorldMatrix;

IDirect3DDevice9* Device = 0;
IDirect3DVertexBuffer9* VB = 0;
IDirect3DIndexBuffer9* IB = 0;

const int m_width = 800;
const int m_height = 600;

float m_cameraPointZ = 0.0f;
float m_cameraPointX = 0.0f;

void SetupCamera()
{
	D3DXVECTOR3 position(0.0f + m_cameraPointX, 5.0f, -5.0f + m_cameraPointZ);
	D3DXVECTOR3 target  (0.0f + m_cameraPointX, 0.0f, 0.0f + m_cameraPointZ);
	D3DXVECTOR3 up      (0.0f, 1.0f, 0.0f);
	D3DXMATRIX V;
	D3DXMatrixLookAtLH(&V, &position, &target, &up);
	Device->SetTransform(D3DTS_VIEW, &V);

	D3DXMATRIX projection;
	D3DXMatrixPerspectiveFovLH(&projection, D3DX_PI*0.5f, (float)m_width/(float)m_height, 1.0f, 1000.0f);
	Device->SetTransform(D3DTS_PROJECTION, &projection);
	Device->SetRenderState(D3DRS_LIGHTING, false);
}

bool Setup()
{
	Device->CreateVertexBuffer( 8*sizeof(ColorVertex), D3DUSAGE_WRITEONLY, ColorVertex::FVF, D3DPOOL_MANAGED, &VB, 0 );
	Device->CreateIndexBuffer( 36*sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &IB, 0 );

	ColorVertex* vertices;
	VB->Lock(0, 0, (void**)&vertices, 0);

	// vertices of a unit cube
	vertices[0] = ColorVertex(-1.0f, -1.0f, -1.0f, d3d::COLOR_RED);
	vertices[1] = ColorVertex(-1.0f,  1.0f, -1.0f, d3d::COLOR_RED);
	vertices[2] = ColorVertex( 1.0f,  1.0f, -1.0f, d3d::COLOR_RED);
	vertices[3] = ColorVertex( 1.0f, -1.0f, -1.0f, d3d::COLOR_RED);
	vertices[4] = ColorVertex(-1.0f, -1.0f,  1.0f, d3d::COLOR_GREEN);
	vertices[5] = ColorVertex(-1.0f,  1.0f,  1.0f, d3d::COLOR_GREEN);
	vertices[6] = ColorVertex( 1.0f,  1.0f,  1.0f, d3d::COLOR_GREEN);
	vertices[7] = ColorVertex( 1.0f, -1.0f,  1.0f, d3d::COLOR_GREEN);

	VB->Unlock();

	// define the triangles of the cube:
	WORD* indices = 0;
	IB->Lock(0, 0, (void**)&indices, 0);

	// front side
	indices[0]  = 0; indices[1]  = 1; indices[2]  = 2;
	indices[3]  = 0; indices[4]  = 2; indices[5]  = 3;

	// back side
	indices[6]  = 4; indices[7]  = 6; indices[8]  = 5;
	indices[9]  = 4; indices[10] = 7; indices[11] = 6;

	// left side
	indices[12] = 0; indices[13] = 4; indices[14] = 5;
	indices[15] = 0; indices[16] = 5; indices[17] = 1;

	// right side
	indices[18] = 7; indices[19] = 3; indices[20] = 2;
	indices[21] = 7; indices[22] = 2; indices[23] = 6;

	// top
	indices[24] = 1; indices[25] = 5; indices[26] = 6;
	indices[27] = 1; indices[28] = 6; indices[29] = 2;

	// bottom
	indices[30] = 4; indices[31] = 0; indices[32] = 3;
	indices[33] = 4; indices[34] = 3; indices[35] = 7;

	IB->Unlock();

	return true;
}

void Cleanup()
{
	d3d::Release<IDirect3DVertexBuffer9*>(VB);
	d3d::Release<IDirect3DIndexBuffer9*>(IB);

//	d3d::Release<IDirect3DVertexBuffer9*>(Triangle);
}

bool Display(float timeDelta)
{
	if( Device )
	{
		SetupCamera();
		D3DXMATRIX Rx, Ry;

		D3DXMatrixRotationX(&Rx, 3.14f/4.0f);

		static float y = 0.0f;
		D3DXMatrixRotationY(&Ry, y);
		y += timeDelta;

		if(y >= 6.28f) y = 0.0f;

		D3DXMATRIX p = Ry;
		Device->SetTransform(D3DTS_WORLD, &p);

		Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);

		Device->BeginScene();

		Device->SetStreamSource(0, VB, 0, sizeof(ColorVertex));
		Device->SetIndices(IB);
		Device->SetFVF(ColorVertex::FVF);
		Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);

		Device->EndScene();

		Device->Present(0, 0, 0, 0);
	}
	return true;
}

LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch( msg )
	{
	case WM_DESTROY:
		::PostQuitMessage(0);
		break;
	case WM_KEYDOWN:
		if( wParam == VK_ESCAPE )
			::DestroyWindow(hwnd);
		else{
			switch(wParam) {
			case VK_UP:
				m_cameraPointZ += 0.5f;
				break;
			case VK_DOWN:
				m_cameraPointZ -= 0.5f;
				break;
			case VK_LEFT:
				m_cameraPointX -= 0.5f;
				break;
			case VK_RIGHT:
				m_cameraPointX += 0.5f;
				break;
			}
		}
		break;
	}
	return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
	if(!d3d::InitD3D(hinstance, m_width, m_height, true, D3DDEVTYPE_HAL, &Device))
	{
		::MessageBox(0, "InitD3D() - FAILED", 0, 0);
		return 0;
	}
		
	if(!Setup())
	{
		::MessageBox(0, "Setup() - FAILED", 0, 0);
		return 0;
	}

	d3d::EnterMsgLoop( Display );

	Cleanup();

	Device->Release();

	return 0;
}